package factories;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Properties;

public class BeanFactory_JDKProxy {

    public static<T> T getBean(Class<T> cls) throws InstantiationException, IllegalAccessException {
        return cls.newInstance();
    }


    public static Object getBean(String id){

        try {
            Properties properties = new Properties();
            properties.load(BeanFactory_JDKProxy.class.getClassLoader().getResourceAsStream("bean.properties"));

            String className = properties.getProperty(id);

            //在不知道业务对象内部具体实现的情况下，要对业务对象内部某些方法【find相关的】进行功能增强【缓存处理】
            /**
             *      *** 动态代理
             *          JDK代理 - 只能基于接口实现动态代理
             *          为什么？？？ -- java是单继承的
             *              $Proxy0 extends Proxy implements Xxx,Yyy
             */

            //目标对象 （需要增强的目标）
            Object target = Class.forName(className).newInstance();

            //返回一个增强功能后的对象 -- 代理对象

            //① 类加载器：和目标对象的类加载器保持一致
            ClassLoader cl = target.getClass().getClassLoader();
            //② 生成的代理对象要实现哪些接口: 和目标对象实现相同的接口
            Class<?>[] clses = target.getClass().getInterfaces();
            //③ 具体增强逻辑的编写位置-回调处理器 (调用代理对象的任何方法，都会触发这个回调对象的invoke方法)
            InvocationHandler hanlder = new InvocationHandler() {
                /**
                 *
                 * @param proxy  当前创建的代理对象 （一般不用）
                 * @param method  当前代理对象调用的方法的反射对象形式
                 * @param args  当前代理对象调用的方法具体参数值
                 * @return
                 * @throws Throwable
                 */
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                    //判断当前调用的是否是find相关方法，如果是，增强
                    String methodName = method.getName();
                    if (methodName.startsWith("find")){
                        //增强
                        System.out.println("缓存增强");
                    }

                    if (methodName.equals("insert")){
                        args[0] = "new-aa";
                    }

                    //调用目标对象的同名方法
                    Object result = method.invoke(target, args);

                    //目标方法后的执行逻辑
                    System.out.println("目标方法后的执行逻辑");
                    return result;
                }
            };
            return Proxy.newProxyInstance(cl,clses,hanlder);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
}
